<?php

# -- DÉBUT NOTE DE LICENCE -------------------------------------
#
# Ce fichier fait partie de Clicpage.
#
# Copyright (c) 2010 Francois (www.clicpage.net)
# Distribué selon les termes de la licence GPL version 2.0.
# Consultez le fichier LICENCE ou
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
#
# -- FIN NOTE DE LICENCE ---------------------------------------

/**
@defgroup CP_PLUGINS	Plugins
*/

/**
@ingroup CP_PLUGINS
@nosubgrouping
@brief Générateur de page

Un instance de cpGenerateur est accessible par la propriété
<var>generateur</var> de chaque instance de cpPage.

Chaque page est associée à un générateur de page, qui est responsable,
entre autres, d'effectuer les actions suivantes:
- Supprimer la page
- Gérer l'interface d'administration de la page
- Gérer l'affichage de la page dans la partie publique du site

*/
class cpGenerateur extends cpMessages
{
	
	
	
	
	
	protected $page;	///< <b>cpPage</b>	Instance de cpPage
	protected $core;	///< <b>cpCore</b>	Instance de cpCore
	
	public $medias = array();	///< <b>array</b>	Médias inclus dans la page
	
	# Pour la partie publique
	protected $commentaireAjoute = false;	///< <b>boolean</b>	Indique si un commentaire a été ajouté
	
	
	
	

	/// @name Initialisation
	//@{
	
	
	/**
	Initialise une instance de cpGenerateur.
	
	@param	page	<b>cpPage</b>		Instance de cpPage
	@param	core	<b>cpCore</b>		Référence à cpCore
	*/
	public function __construct($page, $core)
	{
		$this->page =& $page;
		$this->core =& $core;
	}
	//@}
	
	
	
	
	
	/// @name Nouvelle page
	//@{
	
	
	/**
	Permet de modifier le curseur lors de la création d'une nouvelle page.
	
	@param	cur	<b>cursor</b>	Curseur contenant les informations de la nouvelle page
	*/
	public function curseurNouvellePage($cur)
	{
		
		$options = $cur->page_options;
		if(!is_array($options)) {
			$options = array();
		}
		
		$options['cp'] = array();
		$options['cp']['nouveau'] = true;
		$options['cp']['format'] = $this->core->auth->utilisateur->preference('format');
		$options['cp']['affiche_meta'] = true;
		$options['cp']['affiche_tags'] = true;
		$options['cp']['tags'] = array();
		$options['cp']['medias'] = array();

		$cur->page_options = $options;
		
	}
	//@}
	
	
	
	
	
	/// @name Module d'administration
	//@{
	

	/**
	Appelée à l'initialisation du module d'administration pour
	effectuer des actions comme:
	- définir le titre du module
	- ajouter des boutons d'action
	- définir les actions de formulaire autorisées
	- ...
	
	@param	module	<b>cpModuleAdmin</b>	Module d'administration
	*/
	public function preparerModule($module)
	{
		
	}
	
	
	/**
	Retourne le code HTML de l'interface du module d'administration.
	
	@param	module	<b>cpModuleAdmin</b>	Module d'administration
	@return	<b>string</b>
	*/
	public function adminBody($module)
	{
		return '';
	}
	
	
	/**
	Retourne une portion de code qui sera insérée entre les balises
	<head></head> du module d'administration.
	
	@return	<b>string</b>
	*/
	public function adminHead()
	{
		return '';
	}
	
	
	/**
	Retourne le code HTML présentant les propriétés de la page
	dans le module d'administration (affiché à droite du module).
	
	@param	module		<b>cpModuleAdmin</b>	Module d'administration
	@param	exceptions	<b>array</b>			Identifiants des champs à exclure
	@return	<b>string</b>
	*/
	public function adminProprietesHTML($module, $exceptions = array())
	{
		
		# Combo thèmes
		$themesCombo = array_merge(
			array(__('[thème du site]') => '_default'),
			$this->core->getComboThemes()
		);		

		# Valeur des champs
		if(!$module->erreursFormulairePresentes())
		{
			
			$utilisateur_id 		= (integer) $this->page->utilisateur_id;
			$page_date 				= dt::dt2str('%Y-%m-%d %H:%M', $this->page->page_date);
			$page_format 			= $this->page->page_options['cp']['format'];
			$page_url 				= html::escapeHTML($this->page->page_url);
			$page_theme 			= $this->page->page_theme;
			$page_statut 			= $this->page->page_statut;
			$page_langue 			= $this->page->page_langue;
			$page_commentaires 		= $this->page->page_commentaires;
			$affiche_meta 			= $this->page->page_options['cp']['affiche_meta'];
			$page_acces 			= $this->page->page_acces;
			$page_mot_de_passe 		= !empty($this->page->page_acces_details) && $this->page->page_acces == CP_ACCES_MOT_DE_PASSE ? '               ' : '';
			$page_mot_de_passe_change =	0;
			$page_groupes_autorises	= $this->page->page_acces == CP_ACCES_PERMISSION ? unserialize($this->page->page_acces_details) : array();
			$affiche_tags 			= $this->page->page_options['cp']['affiche_tags'];
			$tags					= $this->page->page_options['cp']['tags'];
						
		}
		else
		{
			
			$utilisateur_id			= (integer) $_POST['utilisateur_id'];
			$page_date				= html::escapeHTML($_POST['page_date']);
			$page_format			= $_POST['page_format'];
			$page_url				= html::escapeHTML($_POST['page_url']);
			$page_theme				= $_POST['page_theme'];
			$page_statut 			= $_POST['page_statut'];
			$page_langue 			= $_POST['page_langue'];
			$page_commentaires 		= $_POST['page_commentaires'];
			$affiche_meta 			= $_POST['affiche_meta'];
			$page_acces 			= $_POST['page_acces'];
			$page_groupes_autorises	= is_array($_POST['page_groupes_autorises']) ? $_POST['page_groupes_autorises'] : array();
			$affiche_tags 			= $_POST['affiche_tags'];
			$tags					= is_array($_POST['tags']) ? $_POST['tags'] : array();
			
			if($_POST['page_mot_de_passe_change'] == '1') {
				$page_mot_de_passe 	= $_POST['page_mot_de_passe'];
				$page_mot_de_passe_change = 1;
			} else {
				$page_mot_de_passe 	= !empty($this->page->page_mot_de_passe) ? '               ' : '';
				$page_mot_de_passe_change = 0;
			}
			
		}
		
		# HTML
		$html = '';
		
		if( (boolean) $this->page->page_modifiee)
		{
			$html.=
			'<p class="brouillon">'.
				__('Ceci est un brouillon.').'<br/>';
			
			if($this->page->page_options['cp']['nouveau']) {
				$html.=
				__('La page n\'a pas encore été publiée.');
			} else {
				$html.=
				'<a href="#" id="restaurer">'.__('Revenir à la version présentement en ligne.').'</a>';
			}
			
			$html.=
			'</p>';
		}
						
		$html.=
			form::hidden('nonce_restaurer', $this->core->genererNonce('restaurerPage')).
			'<div id="modifierPage_accordeon">'.
				'<h3>'.__('Général').'</h3>'.
				'<div>'.
					'<p class="onTop">'.
						'<label for="page_statut">'.__('Statut').'</label>'.
						$module->combo('page_statut', array(
							__('En ligne')		=> CP_STATUT_ONLINE,
							__('Hors ligne')	=> CP_STATUT_OFFLINE
						), $page_statut).
					'</p>'.
					'<p class="onTop">'.
						'<label for="page_url">'.__('URL').'</label>'.
						$module->field('page_url', 40, 200, $page_url).
					'</p>';
			
			$html.= in_array('page_theme', $exceptions) ? '' :
					'<p class="onTop">'.
						'<label for="page_theme">'.__('Thème').'</label>'.
						$module->combo('page_theme', $themesCombo, $page_theme).
					'</p>';
			
			$html.= in_array('page_langue', $exceptions) ? '' :
					'<p class="onTop">'.
						'<label for="page_langue">'.__('Langue de la page').'</label>'.
						$module->combo('page_langue', $this->core->getComboLangues(), $page_langue).
					'</p>';
			
			$html.= in_array('page_format', $exceptions) ? '' :
					'<p class="onTop">'.
						'<label for="page_format">'.__('Format de saisie').'</label>'.
						$module->combo('page_format', array(
							'XHTML' => CP_FORMAT_XHTML,
							'Wiki' => CP_FORMAT_WIKI
						), $page_format).
					'</p>';
						
			$html.= in_array('page_commentaires', $exceptions) ? '' :
					'<p class="onTop">'.
						'<label for="page_commentaires">'.__('Commentaires').'</label>'.
						$module->combo('page_commentaires', array(
							__('Activés') => CP_COMMENTAIRES_ACTIFS,
							__('Utilisateurs avec permission') => CP_COMMENTAIRES_PERMISSION,
							__('Pas de nouveau commentaire') => CP_COMMENTAIRES_READONLY,
							__('Désactivés') => CP_COMMENTAIRES_DESACTIVES
						), $page_commentaires).
					'</p>';
						
			$html.=
				'</div>'.
				'<h3>'.__('Auteur et date').'</h3>'.
				'<div>'.
					'<p class="onTop">'.
						'<label for="utilisateur_id">'.__('Auteur').'</label>'.
						form::hidden('utilisateur_id', $utilisateur_id).
						'<span id="creation_utilisateur_pseudo">'.__('[pas de sélection]').'</span> ';
		$html.= $this->core->auth->verifierPermission('toutesPages') ?
						'<a href="#" id="creation_utilisateur_choisir">'.__('Choisir...').'</a>' : '';
		$html.=
					'</p>'.
					'<p class="onTop">'.
						'<label for="page_date">'.__('Date et heure').'</label>'.
						$module->field('page_date', 40, 200, $page_date).
					'</p>';
						
		$html.= in_array('affiche_meta', $exceptions) ? '' :
					'<p class="onTop">'.
						'<label for="affiche_meta">'.__('Afficher l\'auteur et la date').'</label>'.
						$module->combo('affiche_meta', array(
							__('Oui') => 1,
							__('Non') => 0
						), $affiche_meta).
					'</p>';
		
		$html.=
				'</div>';
		
		if(!in_array('page_acces', $exceptions))
		{
			
			$html.=
				'<h3>'.__('Protection').'</h3>'.
				'<div>'.
					'<p class="onTop">'.
						'<label for="page_acces">'.__('Accès').'</label>'.
						$module->combo('page_acces', array(
							__('Tous les visiteurs') => CP_ACCES_TOUS,
							__('Groupes autorisés seulement') => CP_ACCES_PERMISSION,
							__('Mot de passe') => CP_ACCES_MOT_DE_PASSE
						), $page_acces).
					'</p>'.
					'<p class="onTop acces_mot_de_passe">'.
						'<label for="page_mot_de_passe">'.__('Mot de passe').'</label>'.
						$module->password('page_mot_de_passe', 40, 200, $page_mot_de_passe).
						form::hidden('page_mot_de_passe_change', $page_mot_de_passe_change).
					'</p>'.
					'<p class="onTop acces_groupes">'.
						'<label>'.__('Groupes autorisés').'</label>'.
					'</p>';

			// Liste des groupes
			$groupesUtilisateurs = $this->core->site->getGroupesUtilisateurs(array(), CP_GET_RS);
			while($groupesUtilisateurs->fetch()) {
				$html.=
					'<p class="acces_groupes">'.
						'<label for="page_groupes_autorises['.(integer) $groupesUtilisateurs->groupe_id.']">'.html::escapeHTML($groupesUtilisateurs->groupe_nom).'</label>'.
						form::checkbox('page_groupes_autorises['.(integer) $groupesUtilisateurs->groupe_id.']', '1', in_array($groupesUtilisateurs->groupe_id, $page_groupes_autorises)).
					'</p>';
			}
						
			$html.=
				'</div>';
		
		}
						
		if(!in_array('tags', $exceptions))
		{
			$html.=
				'<h3>'.__('Tags').'</h3>'.
					'<div>'.
						'<ul class="tags">';	
			$noTags = empty($tags) ? '' : ' style="display:none;"';
			$html.=
							'<li class="noTag"'.$noTags.'>'.__('[Pas de tag]').'</li>';
			foreach($tags as $tag)
			{
				$tag = html::escapeHTML($tag);
				$html.=
							'<li>'.
								form::hidden('tags[]', $tag).
								'<span>'.html::escapeHTML($tag).'</span>'.
								'<a class="supprimer_tag" href="#"><img src="images/16/supprimer.png" alt="'.__('Supprimer').'" /></a>'.
							'</li>';	
			}
			$html.=
						'</ul>'.
						'<p class="ajouter_tag">'.
							form::field('tag_texte', 40, 20, '').
							'<input type="button" value="'.__('Ajouter').'" id="ajouter_tag" />'.
						'</p>'.
						'<p class="onTop">'.
							'<label for="affiche_meta">'.__('Afficher les tags').'</label>'.
							$module->combo('affiche_tags', array(
								__('Oui') => 1,
								__('Non') => 0
							), $affiche_tags).
						'</p>'.
					'</div>';

		}
		
		# --COMPORTEMENT-- adminPageApresAccordeonHTML
		$html.= $this->core->executerComportement('adminPageApresAccordeonHTML', $exceptions, $this->page, $module);
		
		$html.=
			'</div>';
							
		return $html;
							
	}
	

	public function adminProprietesEnregistrer($cur, $formulaire, $exceptions = array())
	{
		
		$cur->page_statut			= (integer) $formulaire['page_statut'];
		$cur->page_url				= $formulaire['page_url'];
		$cur->page_date				= dt::dt2str('%Y-%m-%d %H:%M:%S', $formulaire['page_date']);
		$cur->utilisateur_id		= $this->core->auth->verifierPermission('toutesPages') ? 
							(integer) $formulaire['utilisateur_id'] : $this->page->utilisateur_id;
		
		$page_options = $cur->page_options;
		if(!is_array($page_options)) {
			$page_options = array();
		}
		$page_options['cp']['nouveau'] = (boolean) $this->page->page_options['cp']['nouveau'];
		
		if(!in_array('page_theme', $exceptions)) 			{ $cur->page_theme = $formulaire['page_theme']; }
		if(!in_array('page_langue', $exceptions)) 			{ $cur->page_langue = $formulaire['page_langue']; }
		if(!in_array('page_commentaires', $exceptions)) 	{ $cur->page_commentaires = (integer) $formulaire['page_commentaires']; }
		if(!in_array('page_acces', $exceptions)) 			{ $cur->page_acces = (integer) $formulaire['page_acces']; }
		if(!in_array('page_format', $exceptions)) 			{ $page_options['cp']['format'] = (integer) $formulaire['page_format']; }
		if(!in_array('affiche_meta', $exceptions)) 			{ $page_options['cp']['affiche_meta'] = (boolean) $formulaire['affiche_meta']; }
		if(!in_array('tags', $exceptions)) 					{ $page_options['cp']['affiche_tags'] = (boolean) $formulaire['affiche_tags']; }
		
		if($cur->page_acces == CP_ACCES_MOT_DE_PASSE)
		{
			if(empty($formulaire['page_mot_de_passe'])) {
				throw new cpErreur(__('Vous devez indiquer un mot de passe.'), 'page_mot_de_passe', 101);
			}
			elseif($formulaire['page_mot_de_passe_change'] == '1') {
				$cur->page_acces_details = crypt::hmac(CP_MASTER_KEY,$formulaire['page_mot_de_passe']);
			}
		}
		elseif($cur->page_acces == CP_ACCES_PERMISSION)
		{
			
			$groupes_autorises = array();
			$groupesUtilisateurs = $this->core->site->getGroupesUtilisateurs(array(), CP_GET_RS);
			while($groupesUtilisateurs->fetch()) {
				if($formulaire['page_groupes_autorises'][$groupesUtilisateurs->groupe_id] == '1') {
					$groupes_autorises[] = (integer) $groupesUtilisateurs->groupe_id;
				}
			}
			$cur->page_acces_details = serialize($groupes_autorises);
		}
		
		# Tags
		$page_options['cp']['tags'] = array();
		if(is_array($formulaire['tags']))
		{
			foreach($formulaire['tags'] as $tag)
			{
				$tag = trim($tag);
				if(!in_array($tag, $page_options['cp']['tags'])) {
					$page_options['cp']['tags'][] = $tag;
				}
			}
		}
		
		$cur->page_options = $page_options;
		
		# --COMPORTEMENT-- adminPageApresEnregistrerProprietes
		$this->core->executerComportement('adminPageApresEnregistrerProprietes', $exceptions, $this->page, $cur, $formulaire);
		
	}
	
	
	public function adminEnregistrerMediasPage()
	{
		
		# Simplifier la liste des médias
		$medias = array();
		foreach($this->medias as $v)
		{
			if(!is_array($medias[$v[0]])) {
				$medias[$v[0]] = array();
			}
			$medias[$v[0]][$v[1]] = true;
		}

		# Obtenir les médias déjà présents dans la base de données
		$rs = $this->core->con->select('SELECT media_id,page_media_taille FROM '.$this->core->prefix.'pages_medias '.
			'WHERE page_id = '.(integer) $this->page->page_id
		);
		
		# Créer un tableau qui répertorie les médias déjà présents dans la base de données
		$mediasDB = array();
		while($rs->fetch())
		{
			if(!is_array($mediasDB[$rs->media_id])) {
				$mediasDB[$rs->media_id] = array();
			}
			$mediasDB[$rs->media_id][$rs->page_media_taille] = true;
		}

		# Curseur pour ajouter de nouveaux médias dans la base de données
		$cur = $this->core->con->openCursor($this->core->prefix.'pages_medias');
		$cur->page_id = (integer) $this->page->page_id;
		
		# Tableau pour noter les ajouts dans la base de données
		$mediasAjoutes = $mediasDB;
		
		# Lire la liste des médias présents dans la page à publier
		foreach($medias as $media_id => $v)
		{
			
			$media_id = (integer) $media_id;
			
			foreach($v as $taille => $w)
			{
				
				$taille = (integer) $taille;

				# Si le média est déjà présent dans la base de données...
				if(isset($mediasDB[$media_id][$taille]))
				{
					unset($mediasDB[$media_id][$taille]);
				}
				# Si le média n'était pas déjà présent dans la base de données
				# et n'a pas encore été ajouté par cette méthode
				elseif(!isset($mediasAjoutes[$media_id][$taille]))
				{
					
					$cur->media_id = $media_id;
					$cur->page_media_taille = $taille;
					$cur->page_media_statut = $taille == 0 ? CP_MINIATURE_CREEE : CP_MINIATURE_ATTENTE;
					
					$cur->insert();
					
					if(!is_array($mediasAjoutes[$rs->media_id])) {
						$mediasAjoutes[$media_id] = array();
					}
					$mediasAjoutes[$media_id][$taille] = true;
					
				}
				
			}
		}
		
		# On supprime de la DB les médias qui ne font plus partie de la page
		foreach($mediasDB as $media_id => $v)
		{
			foreach($v as $taille => $w)
			{
				$this->core->con->execute('DELETE FROM '.$this->core->prefix.'pages_medias '.
					'WHERE page_id = '.(integer) $this->page->page_id.' AND '.
					'media_id = '.(integer) $media_id.' AND page_media_taille = '.(integer) $taille
				);
			}
		}
		
		return true;
		
	}
	
	
	public function adminTraiterContenu(&$original, &$xhtml, $format)
	{

		if($format == CP_FORMAT_WIKI) {
			$wiki2xhtml = new wiki2xhtml;
			$xhtml = $wiki2xhtml->transform($original);
		} else {
			$xhtml = $original;
		}
		
		$urlAbsolue = preg_quote(CP_URL_PUBLIQUE.'medias/', '#');
		$urlRelative = preg_quote(CP_URL_PUBLIQUE_RELATIVE.'medias/', '#');

		# Repérer les images
		$imgTag = sprintf('<img\s+.*?src="(%s|%s)(.*?)".*?/>', $urlAbsolue, $urlRelative);
		$xhtml = preg_replace_callback('#'.$imgTag.'#i', array($this, 'adminTraiterImage'), $xhtml);
		
		# Repérer les autres médias dans la page
		$lienTag = sprintf('<a\s+.*?href="(?:%s|%s)(.*?)".*?>.*?</a>', $urlAbsolue, $urlRelative);
		$matchesLiens = array();
		preg_match_all('#'.$lienTag.'#i', $xhtml, $matchesLiens);
		
		$objetTag = sprintf('<object\s.*?>(?:\s|.)*?<param name="src" value="(?:%s|%s)(.*?)"\s*?/>(?:\s|.)*?</object>', $urlAbsolue, $urlRelative);
		$matchesObjets = array();
		preg_match_all('#'.$objetTag.'#i', $xhtml, $matchesObjets);
		
		$medias = array_merge($matchesLiens[1], $matchesObjets[1]);
		
		foreach($medias as $media_url)
		{
			$media_url = '/'.$media_url;
			
			# Retirer les paramètres dans l'URL du média
			$media_url = preg_replace('#\?(.*?)$#', '', $media_url);
			
			# Chercher le média dans la base de données
			$media = $this->core->site->getMedias(array(
				'media_url' => $media_url
			), CP_GET_RS);
	
			if(!$media->isEmpty()) {
				$this->medias[] = array($media->media_id, 0);
			}
			
		}
		
		# Repérer les gadgets
		$patternGadget = '<img\s+.*?title="cpGadget".*?/>';
		$xhtml = preg_replace_callback('#'.$patternGadget.'#', array('cpGadgetsContenu', 'traiterContenu'), $xhtml);
		
		# Vider le contenu original s'il est égal au contenu en xhtml
		if($format == CP_FORMAT_XHTML && $original == $xhtml) {
			$original = '';
		}
		
	}
	
	/** @ignore */
	private function adminTraiterImage($match)
	{

		$tailleMax = 0;
		
		# Extraction des attributs
		$widthMatch = array();
		$heightMatch = array();
		$nbWidth = preg_match('#width="([0-9]+)"#', $match[0], $widthMatch);
		$nbHeight = preg_match('#height="([0-9]+)"#', $match[0], $heightMatch);

		# URL du média
		$media_url = '/'.$match[2];
		
		# Retirer les paramètres dans l'URL du média
		$media_url_clean = preg_replace('#\?(.*?)$#', '', $media_url);
		if($media_url_clean != $media_url)
		{
			$pattern = 's=([0-9]+)';
			$matchTaille = array();
			if(preg_match('#'.$pattern.'#', $media_url, $matchTaille)) {
				$tailleMax = (integer) $matchTaille[1];
			}
		}

		# Chercher le média dans la base de données
		$media = $this->core->site->getMedias(array(
			'media_url' => $media_url_clean
		), CP_GET_STATIC);

		if($media->isEmpty()) {
			return $match[0];
		}

		if($media->media_type != 'image/jpeg') {
			$this->medias[] = array($media->media_id, 0);
		}

		# On sait maintenant que le média existe dans la base de données
		
		# Déterminer les dimensions souhaitées du média
		if($nbWidth && $nbHeight && $tailleMax == 0) {
			$width = (integer) $widthMatch[1];
			$height = (integer) $heightMatch[1];
			$tailleMax = $width > $height ? $width : $height;
		} elseif($tailleMax != 0) {
			$this->medias[] = array($media->media_id, 30);
			return $match[0];
		}

		# Obtenir les dimensions réelles du média
		$f = $media->cheminFichier();
		if(($info = @getimagesize($f)) === false) {
			$this->medias[] = array($media->media_id, 0);
			return $match[0];
		}

		if(!($info[0] >= $info[1] && $tailleMax < $info[0]) && !($info[1] >= $info[0] && $tailleMax < $info[1])) {
			$this->medias[] = array($media->media_id, 0);
			return $match[0];
		}
		$this->medias[] = array($media->media_id, $tailleMax);

		# Donner une nouvelle source à l'image
		$src = $media_url == $media_url_clean ?
			$match[1].$match[2].'?s='.$tailleMax :
			$match[1].$match[2].'&s='.$tailleMax;
		return preg_replace('#src="(.+?)"#', sprintf('src="%s"', $src), $match[0]);
		
	}
	//@}
	
	
	
	
	
	/// @name Publier et supprimer
	//@{
	
	
	/**
	Publie la page.
	
	Transfère les valeurs du brouillon dans 'cp_pub_pages', puis
	supprime le brouillon de 'cp_temp_pages'.
	
	Note: Cette méthode ne va pas chercher les données dans la base de
	données. Elle se contente d'utiliser les valeurs des propriétés de cpPage.
	*/
	public function publier()
	{	
		if($this->page->getVersion() == CP_TEMPORAIRE)
		{
			
			$this->page->page_options['cp']['nouveau'] = false;
			
			$cur = $this->core->con->openCursor($this->core->prefix.'pub_pages');
			
			$cur->cat_id = (integer) $this->page->cat_id;
			$cur->page_theme = $this->page->page_theme;
			$cur->page_statut = (integer) $this->page->page_statut;
			$cur->page_modifiee = CP_PAGEMODIFIEE_NON;
			$cur->page_langue = $this->page->page_langue;
			$cur->page_url = $this->page->page_url;
			$cur->page_titre = $this->page->page_titre;
			$cur->page_entete = $this->page->page_entete;
			$cur->page_entete_xhtml = $this->page->page_entete_xhtml;
			$cur->page_contenu = $this->page->page_contenu;
			$cur->page_contenu_xhtml = $this->page->page_contenu_xhtml;
			$cur->page_options = serialize($this->page->page_options);
			$cur->page_commentaires = (integer) $this->page->page_commentaires;
			$cur->page_acces = (integer) $this->page->page_acces;
			$cur->page_acces_details = $this->page->page_acces_details;
			$cur->page_date = $this->page->page_date;
			$cur->page_date_modification = $this->page->page_date_modification;
			$cur->utilisateur_id = (integer) $this->page->utilisateur_id;
			$cur->modification_utilisateur_id = (integer) $this->page->modification_utilisateur_id;
			$cur->page_mots = $this->page->page_mots;
			
			$cur->update('WHERE page_id = '.(integer) $this->page->page_id);
			
			$this->core->con->execute('DELETE FROM '.$this->core->prefix.'temp_pages '.
						  'WHERE page_id = '.(integer) $this->page->page_id);
			
			$this->page->page_modifiee = CP_PAGEMODIFIEE_NON;
			
			# Tags	
			$this->core->con->execute('DELETE FROM '.$this->core->prefix.'tags WHERE page_id = '.(integer) $this->page->page_id);
			$cur = $this->core->con->openCursor($this->core->prefix.'tags');
			$cur->page_id = (integer) $this->page->page_id;
			foreach($this->page->page_options['cp']['tags'] as $tag)
			{
				$cur->tag_texte = $tag;
				$cur->insert();
			}

		}
	}
	
	
	/**
	Supprime la page
	*/
	public function supprimer()
	{
	
		# --COMPORTEMENT-- coreAvantSupprimerPage
		$this->core->executerComportement('coreAvantSupprimerPage', $this);
		
		if($this->page->isCatHome()) {
			$cur = $this->core->con->openCursor($this->core->prefix.'categories');
			$cur->home_page_id = null;
			$cur->update('WHERE cat_id = '.(integer) $this->page->cat_id);
		}
		
		$strReq = 'DELETE FROM '.$this->core->prefix.'temp_pages WHERE page_id = '.(integer) $this->page->page_id;
		$this->core->con->execute($strReq);
		
		$strReq = 'DELETE FROM '.$this->core->prefix.'pub_pages WHERE page_id = '.(integer) $this->page->page_id;
		$this->core->con->execute($strReq);
		
		# --COMPORTEMENT-- coreApresSupprimerPage
		$this->core->executerComportement('coreApresSupprimerPage', $this);
		
	}
	//@}
	
	
	
	
	
	/// @name Public
	//@{
	
	
	/**
	Permet d'effectuer des actions avant l'affichage de la page.
	Par exemple, traiter des données de formulaire.
	
	Par défaut, cette fonction se charge de traiter les commentaires
	envoyés par les utilisateurs.
	*/
	public function initPublic()
	{
		
		# Ajout d'un commentaire
		if(	$_POST['action'] == 'poster_commentaire' &&
			$_POST['nonce'] == $_SESSION['nonces']['public_commentaires'][$this->page->page_id]
		) {
			unset($_SESSION['nonces']['public_commentaires'][$this->page->page_id]);
			$this->ajouterCommentaire($_POST);
		}
		
		# --COMPORTEMENT-- publicInitPage
		$this->core->executerComportement('publicInitPage', $this->page);
		
	}
	
	
	/**
	Envoie la page au navigateur: les headers, puis le contenu HTML.
	
	Appelé juste après la fonction 'initPublic' ci-dessus.
	*/
	public function afficher()
	{
		$this->chargerTheme();		
		$this->theme->envoyerHeaders();
		$this->theme->afficherPage();	
	}
	
	
	/**
	Prépare une instance de cpTheme et l'affecte à $this->theme.
	*/
	public function chargerTheme()
	{
		
		if($this->page->page_theme == '_default') {
			$theme_identifiant = $this->core->site->getPropriete('site_theme');
		} else {
			$theme_identifiant = $this->page->page_theme;
		}
		
		$this->theme = $this->core->getObjetTheme($theme_identifiant);
		$this->theme->setPage($this->page);
		
	}
	
	
	/**
	Renvoie le nom du fichier de thème à utiliser (sans le .html)
	Par défaut: 'page'
	
	Est appelée à l'intérieur de cpTheme.
	
	@return	<b>string</b>
	*/	
	public function getFichierTheme()
	{
		return 'page';
	}
	
	
	/**
	Renvoie le code HTML à utiliser pour afficher les pages de recherche
	ou de liens.
	*/
	public function public_apercu($affiche_extrait, $suite = false)
	{
		
		$html = '';
		
		if($affiche_extrait)
		{
			if($this->page->page_entete_xhtml != '') {
				$entete = $this->page->page_entete_xhtml;
			} elseif($this->page->page_contenu_xhtml != '') {
				$entete = $this->page->page_contenu_xhtml;
			} else {
				$entete = '<p>'.__('[pas d\'extrait]').'</p>';
			}
			
			$html.=
			'<div class="liens-lien">'.
				'<a class="liens-lien-titre" href="'.html::escapeHTML(CP_URL_PUBLIQUE_RELATIVE.$this->page->page_url).'">'.html::escapeHTML($this->page->page_titre).'</a>';
			
			if($this->affiche_meta()) {
				$html.=
				'<p class="liens-lien-meta">'.sprintf(__('Publié par %s'), $this->public_auteur_pseudo()).', '.cpDt::belleDate(array('le' => true), strtotime($this->page->page_date)).'</p>';
			}
			
			$html.=
				'<p class="liens-lien-extrait">'.text::cutString(html::clean($entete),300).'</p>';
			
			if($suite) {
				$html.= '<p class="liens-lien-suite"><a href="'.html::escapeHTML(CP_URL_PUBLIQUE_RELATIVE.$this->page->page_url).'">'.__('Lire la suite...').'</a></p>';
			}
			
			$html.=
			'</div>';
		}
		else
		{
			$html.=
			'<li class="liens-lien">'.
				'<a class="liens-lien-titre" href="'.html::escapeHTML(CP_URL_PUBLIQUE_RELATIVE.$this->page->page_url).'">'.html::escapeHTML($this->page->page_titre).'</a>'.
			'</li>';
		}
		
		return $html;
		
	}
	//@}
	
	
	
	

	/// @name Balises de template
	//@{
	
	public function public_head()
	{
		return '';
	}
	
	public function public_titre()
	{
		return $this->page->page_titre;
	}
	
	public function public_url()
	{
		return $this->page->page_url;
	}
	
	public function public_entete()
	{
		return $this->page->page_entete_xhtml;
	}
	
	public function public_contenu()
	{
		return $this->page->page_contenu_xhtml;
	}
	
	public function public_date_creation()
	{
		return $this->page->page_date;
	}
	
	public function public_date_modification()
	{
		return $this->page->page_date_modification;
	}
	
	public function public_auteur_pseudo()
	{
		return $this->page->getAuteur()->utilisateur_pseudo;
	}
	
	public function public_auteur_prenom()
	{
		return $this->page->auteur()->utilisateur_prenom;
	}
	
	public function public_auteur_nom()
	{
		return $this->page->getAuteur()->utilisateur_nom;
	}
	
	public function public_auteur_email()
	{
		return $this->page->getAuteur()->utilisateur_email;
	}
	
	public function affiche_meta()
	{
		return $this->page->page_options['cp']['affiche_meta'];
	}
	
	public function affiche_tags()
	{
		return $this->page->page_options['cp']['affiche_tags'];
	}
	
	public function public_langue()
	{
		return $this->page->page_langue;
	}
	//@}
	
	
	
	
	
	/// @name Commentaires
	//@{
	
	
	/**
	Renvoie un identifiant qui sera placé dans le champ 
	commentaire_contexte de la table de commentaires si un
	commentaire est ajouté sur la page.
	
	Par défaut: (integer) 0
	
	@return	<b>integer</b>
	*/
	public function getContexteCommentaires()
	{
		return 0;
	}
	
	
	/**
	Renvoie un boolean indiquant si les commentaires sont
	actifs sur la page.
	
	@return	<b>boolean</b>
	*/
	public function commentairesActifs()
	{
		return in_array($this->page->page_commentaires, array(CP_COMMENTAIRES_ACTIFS, CP_COMMENTAIRES_PERMISSION));
	}

	
	/**
	Renvoie le code HTML du formulaire de commentaires.
	
	@return	<b>string</b>
	*/
	public function formulaireCommentaires()
	{
		
		if($this->page->page_commentaires == CP_COMMENTAIRES_ACTIFS ||
		   ($this->page->page_commentaires == CP_COMMENTAIRES_PERMISSION &&
		    $this->core->auth->estConnecte()
		   )
		)
		{
			if(!$this->commentaireAjoute && $_POST['action'] == 'poster_commentaire') {
				$commentaire_auteur = $_POST['commentaire_auteur'];
				$commentaire_email = $_POST['commentaire_email'];
				$commentaire_titre = $_POST['commentaire_titre'];
				$commentaire_contenu = $_POST['commentaire_contenu'];
			}
			
			$nonce = $_SESSION['nonces']['public_commentaires'][$this->page->page_id] = sha1(uniqid(rand(),true));
					
			$html =
			'<form id="formulaire-commentaire" action="'.$_SERVER['REQUEST_URI'].'#formulaire-commentaire" method="post">'.
				form::hidden('action', 'poster_commentaire').
				form::hidden('page_id', $this->page->page_id).
				form::hidden('nonce', $nonce).
				$this->afficherMessages().
				'<p>'.
					'<label for="commentaire_auteur">Votre pseudonyme</label>'.
					$this->field('commentaire_auteur', 40, 80, html::escapeHTML($commentaire_auteur)).
				'</p>'.
				'<p>'.
					'<label for="commentaire_email">Votre adresse électronique</label>'.
					$this->field('commentaire_email', 40, 80, html::escapeHTML($commentaire_email)).
				'</p>';
				
			if($this->core->site->getPropriete('commentaire_titre') == '1')
			{
				$html.=
				'<p>'.
					'<label for="commentaire_titre">Titre de votre commentaire</label>'.
					$this->field('commentaire_titre', 40, 250, html::escapeHTML($commentaire_titre)).
				'</p>';
			}
			
			$html.=
				'<p>'.
					'<label for="commentaire_contenu">Votre commentaire</label>'.
					$this->textArea('commentaire_contenu', 40, 5, html::escapeHTML($commentaire_contenu)).
				'</p>'.
				'<input type="submit" value="Envoyer le commentaire" />'.
			'</form>';
		
		}
		elseif($this->page->page_commentaires == CP_COMMENTAIRES_PERMISSION)
		{
			$html = '<p>Vous devez vous connecter pour rédiger un commentaire.</p>';
		}
		
		return $html;
		
	}
	
	
	/**
	Ajoute un commentaire à la page.
	
	@param	formulaire	<b>array</b>	Données de formulaire
	*/
	public function ajouterCommentaire($formulaire)
	{

		try
		{
		
		if(	$this->page->page_commentaires == CP_COMMENTAIRES_ACTIFS ||
			($this->page->page_commentaires == CP_COMMENTAIRES_PERMISSION &&
			 $this->core->auth->estConnecte() )
		) {
			
			$moderer_commentaires = (integer) $this->core->site->getPropriete('moderer_commentaires');
			
			$cur = $this->core->con->openCursor($this->core->prefix.'commentaires');
			$cur->page_id = (integer) $this->page->page_id;
			$cur->commentaire_contexte = (integer) $this->getContexteCommentaires();
			$cur->commentaire_statut = $moderer_commentaires == 1 ? CP_COMMENTAIRE_ATTENTE : CP_COMMENTAIRE_APPROUVE;
			$cur->utilisateur_id = $this->core->auth->estConnecte() ? $this->core->auth->getUtilisateurID() : null;
			$cur->commentaire_ip = http::realIP();
			$cur->commentaire_auteur = $formulaire['commentaire_auteur'];
			$cur->commentaire_email = $formulaire['commentaire_email'];
			$cur->commentaire_titre = isset($formulaire['commentaire_titre']) ? $formulaire['commentaire_titre'] : null;
			$cur->commentaire_contenu = $formulaire['commentaire_contenu'];
			
			$this->core->site->creerCommentaire($cur);
			
			$this->commentaireAjoute = true;
			
			if($cur->commentaire_statut == CP_COMMENTAIRE_APPROUVE) {				
				$this->messageOK(__('Votre commentaire a été publié.'));
			} else {
				$this->messageOK(__('Votre commentaire a été enregistré et sera publié après validation.'));
			}

		}
		
		} catch (cpErreur $e) {
			if($e->getCode() >= 100 && $e->getCode() <= 199) {
				$this->ajouterErreurFormulaire($e->getChamp(), $e->getMessage());
			} else {
				$this->erreurGenerale($e);
			}
		}
		
	}
	//@}
	
}

?>